﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using XMK.Framework.Model.Sp;
using XMK.Utils;
using XMK.Framework.DataAccess;

namespace XMK.Framework
{
    internal class SpHelper
    {
        #region 私有变量
        private static readonly string CacheMethodID = "XMK.Framework.SP.ASSEMBLY.METHOD.CACHE";
        private static BindingFlags MethodBinding = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
        #endregion
        /// <summary>
        /// 根据别名获取方法
        /// </summary>
        /// <param name="methodAlias">Ajax别名</param>
        /// <returns>调用方法</returns>
        internal static SpMethod GetSpMethod(string methodAlias)
        {
            Dictionary<string, SpMethod> dict = CacheHelper<Dictionary<string, SpMethod>>.GetCacheValue(CacheMethodID);
            if (dict.ContainsKey(methodAlias))
                return dict[methodAlias];
            else
                return null;
        }
        /// <summary>
        /// 解析SpMapping.xml文件
        /// </summary>
        /// <returns>SpMapping.xml的解析后对象</returns>
        internal static SpMappingInfo LoadSpMapping(string mappingFilePath)
        {
            return XmlHelper.Deserialize<SpMappingInfo>(mappingFilePath);
        }
        /// <summary>
        /// 把ajax方法配置转换成实际的对象并存储在缓存中
        /// </summary>
        /// <param name="spMappingInfos">AjaxMapping.xml的解析后对象</param>
        internal static void InitSpMethod(DbProvider dbProvider,SpMappingInfo spMappingInfos)
        {
            List<Assembly> assemblys = GetMappingAssemblys(spMappingInfos.Assemblies);
            Dictionary<string, Type> typeDict = new Dictionary<string, Type>();
            Dictionary<string, SpMethod> methods = new Dictionary<string, SpMethod>();

            foreach (DataMappingInfo dataClassMappingInfo in spMappingInfos.DataMappings)
            {
                #region 初始化类信息
                Type type = GetType(assemblys, typeDict, dataClassMappingInfo.Name);
                Object instance = null;
                if (type != null)
                {
                    // 增加数据连接字符串
                    if (!string.IsNullOrEmpty(dataClassMappingInfo.DbConn))
                    {
                        instance = Activator.CreateInstance(type, Config.ConfigHelper.GetDbProvider(dataClassMappingInfo.DbConn));
                    }
                    else
                    {
                        instance = Activator.CreateInstance(type, dbProvider);
                    }
                }
                else
                {
                    throw new Exception(String.Format(ErrorResource.AjaxMappingBizNotFound, dataClassMappingInfo.Name));
                }
                #endregion
                if (dataClassMappingInfo.MethodMappings != null && dataClassMappingInfo.MethodMappings.Count > 0)
                {
                    foreach (MethodMappingInfo spMethod in dataClassMappingInfo.MethodMappings)
                    {
                        #region 初始化参数信息
                        List<Type> paramTypes = new List<Type>();
                        paramTypes.Add(Type.GetType("System.String"));
                        if (!String.IsNullOrEmpty(spMethod.ParaTypes))
                        {
                            string[] parameterTypes = spMethod.ParaTypes.Split(',', ';');
                            for (int index = 0; index < parameterTypes.Length; index++)
                            {
                                if (string.IsNullOrEmpty(parameterTypes[index])) continue;
                                //把系统定义的短类型转为实际类型
                                string systemType = TypeHelper.GetBaseDataType(parameterTypes[index]);
                                Type t = null;
                                //如果不为空，则为系统类型
                                if (!string.IsNullOrEmpty(systemType))
                                {
                                    t = Type.GetType(systemType);
                                }
                                //否则就是自定义类型
                                else
                                {
                                    t = GetType(assemblys, typeDict, parameterTypes[index]);
                                    if (t == null || !t.IsClass || t.IsAbstract)
                                        throw new Exception(String.Format(ErrorResource.AjaxMappingParamNotFound, parameterTypes[index]));
                                }
                                paramTypes.Add(t);
                            }
                        }
                        #endregion
                        #region 初始化方法信息
                        MethodInfo method = type.GetMethod(spMethod.MethodName, MethodBinding, null, paramTypes.ToArray(), null);

                        #endregion
                        if (method != null)
                            methods.Add(spMethod.SpName, new SpMethod(instance, method));
                    }
                }
            }
            CacheHelper<Dictionary<string, SpMethod>>.SetCache(CacheMethodID, methods);
        }
        #region 私有方法
        /// <summary>
        /// 获取AjaxMapping配置的缓存程序集
        /// </summary>
        /// <param name="assemblie">程序集字符串</param>
        /// <returns>程序集数组</returns>
        private static List<Assembly> GetMappingAssemblys(string assemblie)
        {
            if (assemblie == null)
            {
                throw new Exception(ErrorResource.AjaxMappingAssemblyNotFound);
            }
            string[] assemblies = assemblie.Split(',');
            List<Assembly> assemblyList = new List<Assembly>(assemblies.Length);
            foreach (string assem in assemblies)
            {
                assemblyList.Add(Assembly.Load(assem));
            }
            return assemblyList;
        }
        /// <summary>
        /// 在程序集中获取类型
        /// </summary>
        /// <param name="assemblieList">程序集列表</param>
        /// <param name="typeDict">类型列表</param>
        /// <param name="typeName">类型名称</param>
        /// <returns>获取类型名对应的的类型对象</returns>
        private static Type GetType(List<Assembly> assemblieList, Dictionary<string, Type> typeDict, string typeName)
        {
            if (typeDict.ContainsKey(typeName))
                return typeDict[typeName];
            Type type = null;
            foreach (Assembly assembly in assemblieList)
            {
                type = assembly.GetType(typeName, false);
                if (type != null) break;
            }
            typeDict[typeName] = type;
            return type;
        }
        #endregion
    }
}
